[PY3]——物件導向程式設計(1)

Jelly_lyj發表於2017-03-18

類的物件

有三種物件

可以做什麼操作

包括什麼屬性

類物件

屬性引用、例項化

函式方法、內建的屬性、類變數

例項物件

屬性引用

函式方法、類變數、例項變數

方法物件

 

 

 

1. 類物件、例項物件、方法物件

類[class]是抽象的模型
例項[instance]是根據類建立出來的一個個具體的“物件”

1.1  如何定義類

class 類名(表示該類是從哪個類繼承下來的): 
  xxx

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

1.2  屬性引用

class Myclass(object):
    '''A simple example about class'''
    i=123
    def f(self):
        return "hello world"
    def __init__(self,name,score):
        self.name=name
        self.score=score

# 引用類變數、方法,都是合理的屬性引用,分別返回一個整數和一個函式物件
print(Myclass.i)
123
print(Myclass.f) ->這就叫做建立了方法物件,但要注意這只是建立了物件但不是呼叫了這個方法
<function Student.f at 0x7f81f42c58c8>

# 類還有內建的屬性可以被引用
print(Myclass.__doc__)
A simple example about class
print(Myclass.__name__)
Myclass
print(Myclass.__dict__)
{'__doc__': 'A simple example about class', '__init__': <function Myclass.__init__ at 0x7f0bf8fd0950>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Myclass' objects>, 'i': 123, '__dict__': <attribute '__dict__' of 'Myclass' objects>, 'f': <function Myclass.f at 0x7f0bf8fd08c8>}
print(Myclass.__module__)
__main__
print(Myclass.__bases__)
(<class 'object'>,)
內建類 描述
__dict__ 類的屬性
__doc__ 類的文件字串
__name__ 類名
__module__ 類定義所在的模組
__bases__ 類的所有父類構成元素

1.3 例項化操作

# 例項化操作如下所示,賦值給一個變數,就能夠建立一個例項物件
x=Myclass()
y=Myclass()
print(x.i) 
123
print(x.f())
hello world
print(x.__doc__)
A simple example about class

# 建立的例項物件可以自由地繫結屬性
x.iii="a9a"
print(x.iii)
a9a
# 建立的每個例項物件的記憶體地址都不一樣
print(x)
<__main__.Myclass object at 0x7fbe7fa53160>
print(y)
<__main__.Myclass object at 0x7fbe7f7a8630>

1.4 __init__

# 上述的例項化操作建立了一個空的object
# 但在很多情況下,我們建立例項物件時,可能都需要有特定的初始狀態。這個由__init__方法實現。
# 當一個類定義了 __init__() 方法, 類在例項化時會自動呼叫 __init__() 方法, 用於建立新的類例項

class Myclass(object): '''A simple example about class''' i=123 def f(self): return "hello world" def __init__(self,name,score): self.name=name self.score=score # 關於__init__,要注意的是:
(1) __init__方法的第一個引數永遠是self,表示建立的例項本身

(2) 有了__init__方法,在建立例項時就不能傳入空的引數了,必須傳入匹配的引數

x=Myclass() TypeError: __init__() missing 2 required positional arguments: 'name' and 'score' x=Myclass("J",11) print(x.name,x.score) J 11

 

2. 屬性之“變數屬性”、作用域問題、訪問限制問題

2.1  類變數、例項變數、作用域

class test:
    x=7                    #類的直接下級作用域的變數,叫做類變數

    def __init__(self,name):
        self.name=name      #例項中的變數,叫例項變數


instance1=test("name1")
instance2=test('name2')

# 類變數:既是類物件可見的屬性、也是例項物件可見的屬性
print(test.x)
7

print(instance1.x)
7

# 下面的例子中,instance1.x+=100本質是例項物件instance1新建了一個屬性,覆蓋了instance1.x這個變數
# 我們要知道,類變數可以是類物件的屬性也可以是例項物件的屬性,但例項物件的屬性變化影響不了類物件的屬性,也不會影響其他的例項物件
# 反之,類物件屬性的變化倒是能影響例項物件的屬性
test.x=100
print(instance1.x)
100
print(test.x)
100

instance1.x+=100
print(instance1.x)
107
print(test.x)
100
print(instance2.x)
100

2.2 訪問限制

# 如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__,在Python中,例項的變數名如果以__開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問
# 這樣就確保了外部程式碼不能隨意修改物件內部的狀態,這樣通過訪問限制的保護,程式碼更加健壯

class Student(object):
    def __init__(self,name,score):
        self.__name=name
        self.__score=score

stu=Student('J',100)
print(stu.__score)
AttributeError: 'Student' object has no attribute '__score'


# 如果要允許外部訪問者兩個變數,可以增加get方法(get_name()和get_score())
# 如果又要允許外部修改這兩個變數,可以增加set_score,雖然顯得大費周折,但我們可以順帶對引數做個檢查

class Student(object):
    def __init__(self,name,score):
        self.__name=name
        self.__score=score

    def get_name(self):
        return '{}'.format(self.__name)

    def get_score(self):
        return '{}'.format(self.__score)

    def print_stu(self):
        print('%s:%s' % (self.__name,self.__score))

    def set_score(self,score):
        if 0<=score<=100:
            self.__score=score
        else:
            raise ValueError('bad score')


stu=Student('J',100)
print(stu.get_name())
J
print(stu.get_score())
100
stu.print_stu()
J:100

stu.set_score(
99);print(stu.get_score()) 99 stu.set_score(101) ValueError: bad score

 

 3. 父類、子類(繼承、多型)

# 基類/父類/超類(base class/super class) <—— 子類(subclass)

class Animal(object):
    def run(self):
        print("Animal is running...")

    def run2(self):
        print("111")

class Dog(Animal):
    def run(self):
        print("Dog is running...")

class Cat(Animal):
    def run(self):
        print("Cat is running...")

animal=Animal()
dog=Dog()
cat=Cat()

# 子類父類存在同名方法時,子類方法覆蓋父類方法
dog.run()
Dog is running...
dog.run2()
111
cat.run()
Cat is running...

# 可以通過isinstance(obj, class_or_tuple, /),可以判斷一個instance object是否屬於某個類
print(isinstance(dog,Dog))
True
print(isinstance(dog,Animal))
True
print(isinstance(animal,Dog))
False

# issubclass(cls, class_or_tuple, /)class Base:
    Public_class_var='public class var'     #類變數(public)
    __Private_class_var='private class var' #類變數(private)

    def __init__(self):
        self.public_instance_var='public instance var'     #例項變數(public)
        self.__private_instance_var='private instance var' #例項變數(private)

    def public_instance_method(self):
        return 'public instance method'

    def __private_instance_method(self):
        return 'private instance method'

    @classmethod
    def public_class_method(cls):
        return 'public class method'

    @classmethod
    def __private_class_method(cls):
        return 'private class method'

    @staticmethod
    def public_static_method():
        return 'public static method'

    @staticmethod
    def __private_static_method():
        return 'private static method'

class Sub(Base):
   pass

sub=Sub()
print(sub.__dict__)
{'_Base__private_instance_var': 'private instance var', 'public_instance_var': 'public instance var'}

# 子類可以繼承類變數(public)、例項變數(public) class Sub(Base): def print_public_var(self): print(self.Public_class_var) def print_public_instance_var(self): print(self.public_instance_var) sub=Sub() sub.print_public_var() public class var sub.print_public_instance_var() public instance var # 事實上凡是公有的都能繼承,凡是私有的都不能繼承 class Sub(Base): def print_public_class_method(self): print(self.public_class_method()) def print_public_static_method(self): print(self.public_static_method()) def print_public_instance_method(self): print(self.public_instance_method()) sub=Sub() sub.print_public_class_method() public class method sub.print_public_static_method() public static method sub.print_public_instance_method() public instance method

 

 4. classmethod、staticmethod

class A(object):
    def foo(self,x):
        print("executing foo({},{})".format(self,x))

    @classmethod
    def class_foo(cls,x):
        print("executing class_foo({},{})".format(cls,x))

    @staticmethod
    def static_foo(x):
        print("executing static_foo({})".format(x))

a=A()

a.foo(1)
executing foo(<__main__.A object at 0x7fe8619c7160>,1)

a.class_foo(1)
executing class_foo(<class '__main__.A'>,1)

a.static_foo(1)
executing static_foo(1)

a.static_foo('hi')
executing static_foo(hi)

A.class_foo(1)
executing class_foo(<class '__main__.A'>,1)

A.static_foo(1)
executing static_foo(1)

A.foo(1)TypeError: foo() missing 1 required positional argument: 'x'

print(a.foo)
<bound method A.foo of <__main__.A object at 0x7f57d0ba41d0>>

print(a.class_foo)
<bound method A.class_foo of <class '__main__.A'>>

print(a.static_foo)
<function A.static_foo at 0x7f71b0c89b70>

 

參考文章

《Python3文件——類》

《極客學院——從零開始學python——類(3)》

《廖雪峰——物件導向——訪問限制》

相關文章