类变量的访问限制
class Data:
def __init__(self, arg1, arg2):
self.__arg1 = arg1
self.__arg2 = arg2
def print_args(self):
print(f"arg1:{self.__arg1}, arg2:{self.__arg2}")
data = Data("1", 2)
data.print_args() # arg1:1, arg2:2
print(data.__arg1) # 报错 'Data' object has no attribute 'arg1'
print(data.__arg2) # 报错 'Data' object has no attribute 'arg2'
当变量名为 __arg1
这样的形式时,类的示例就不能直接访问。
因为 Python 解释器将 __arg1
改成了 _Data__arg1
。
data = Data("1", 2)
print(data._Data__arg1) # 1
获取对象的信息
对象的类型
type(data) # __main__.Data
比对对象类型
isinstance(data, Data) # True
判断是否是函数
import types
def my_func():
... # 三个点相当于 pass
type(my_func) == types.FunctionType # True
type(max) == types.BuiltinFunctionType # True
type(lambda x: x*x) == types.LambdaType # True
type((x for x in [1, 2, 3])) == types.GeneratorType # True
获取对象的所有属性和方法
dir(data)
"""
['_Data__arg1',
'_Data__arg2',
'__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'print_args']
"""
demo_str = "demo_str"
dir(demo_str)
"""
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getnewargs__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmod__',
'__rmul__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'capitalize',
'casefold',
'center',
'count',
'encode',
'endswith',
'expandtabs',
'find',
'format',
'format_map',
'index',
'isalnum',
'isalpha',
'isascii',
'isdecimal',
'isdigit',
'isidentifier',
'islower',
'isnumeric',
'isprintable',
'isspace',
'istitle',
'isupper',
'join',
'ljust',
'lower',
'lstrip',
'maketrans',
'partition',
'replace',
'rfind',
'rindex',
'rjust',
'rpartition',
'rsplit',
'rstrip',
'split',
'splitlines',
'startswith',
'strip',
'swapcase',
'title',
'translate',
'upper',
'zfill']
"""
操作属性
获取属性
getattr()
getattr(data, "_Data__arg1") # 1
设置属性
setattr()
setattr(data, "name", "ok")
print(data.name) # ok
判断是否有属性
hasattr()
hasattr(data, "_Data__arg1") # True
实例属性和类属性
实例属性
class Data:
def __init__(self):
self.name = "name"
data = Data()
print(data.name) # name
限制实例能添加的属性
class Data:
__slots__ = ("name", "age") # 用元组定义允许添加的属性名称
data = Data()
data.name = "name" # 不报错
data.num = "num" # AttributeError: 'Data' object has no attribute 'num'
class Data2(Data):
pass
data2 = Data2()
data2.num = "num" # 不报错
__slots__
仅对当前类有效,对子类无效。
类属性
class Data:
name = "name"
def __init(self):
pass
data = Data()
print(data.name) # name
实例方法
给单个实例绑定方法
class Data:
def __init__(self):
pass
from types import MethodType
def get_name(self): # 注意这里要加 self
return "name"
data = Data()
data.get_name = MethodType(get_name, data)
print(data.get_name()) # name
data2 = Data()
print(data2.get_name()) # AttributeError: 'Data' object has no attribute 'get_name'
这个方法仅对当前示例有效。
给所有实例绑定方法
class Data:
def __init__(self):
pass
def get_name(self): # 注意这里要加 self
return "name"
Data.get_name = get_name
data = Data()
print(data.get_name()) # name
data2 = Data()
print(data2.get_name()) # name
将方法当作属性使用
class Data:
def __init__(self):
pass
@property
def num(self):
if not hasattr(self, "_num"):
self._num = "None" # 这里注意不要写成 self.num,否则会死循环
return self._num
@num.setter
def num(self, new_num):
self._num = new_num
data = Data()
print(data.num) # None
data.num = "new_num"
print(data.num) # new_num
子类拓展父类
class Father(object):
def get_args(self, *args):
father_args = ["father arg1", "father arg2"]
father_args += args
return father_args
class Son(Father):
def get_args(self, *args):
return super(Son, self).get_args(*args)
son = Son()
son_args = ["son arg1", "son arg2"]
demo = son.get_args(*son_args)
print(demo)
# out
['father arg1', 'father arg2', 'son arg1', 'son arg2']
Python 2 和 3 中 super()
的区别
class A:
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
super().add(x)
b = B()
b.add(2) # 3
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class A(object): # Python2.x 记得继承 object
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
super(B, self).add(x)
b = B()
b.add(2) # 3
定制类
类中定义了 __len__()
方法,就可以用 len()
。
class Data:
def __init__(self):
pass
def __len__(self):
return 100
data = Data()
print(len(data)) # 100
类中定义了 __str__()
方法,就可以用 str()
。
class Data:
def __init__(self):
pass
def __str__(self):
return f"I'm Data"
__repr__ = __str__ # print() 调用 __str__,ipython 交互解释器里直接输出调用 __repr__,这里让他俩输出一样
data = Data()
print(str(data)) # I'm Data
类中定义了 __iter__()
方法,就可以被迭代`。
class Data:
def __init__(self):
self.num = 0
def __iter__(self):
return self
def __next__(self):
self.num += 1
if self.num > 10:
raise StopIteration()
return self.num
for num in Data():
print(num)
"""
1
2
3
4
5
6
7
8
9
10
"""
类中实现了 __getitem__()
方法,可以按照下标取值。
class Data:
def __getitem__(self, n): # n 可以是下标也可以是切片
nums = [1, 2, 3, 4, 5, 6]
if isinstance(n, int):
for index, value in enumerate(nums):
if index == n:
return value
elif isinstance(n, slice):
start = n.start
stop = n.stop
return nums[n.start:n.stop]
data = Data()
print(data[3]) # 4
print(data[2:4]) # [3, 4]
类中实现了 __getattr__
可以动态设置属性,以下是一个将链式调用转为路径的例子。
class Data:
def __init__(self, path=""):
self._path = path
def __getattr__(self, path):
return Data(f"{self._path}/{path}")
def __str__(self):
return self._path
__repr__ = __str__
print(Data().user.name.age.nums) # /user/name/age/nums
类中实现了 __call__
,他的实例就可以直接在后面加 ()
调用。
class Data:
def __call__(self):
print("calling")
data = Data()
data()
判断变量是否可调用
callable(data) # True
枚举类
如果要枚举出十二生肖,除了直接定义常量,更好的方法是用枚举类:
from enum import Enum
Zodiac = Enum(
"Zodiac",
(
"rat",
"cattle",
"tiger",
"rabbit",
"dragon",
"snack",
"horse",
"sheep",
"monkey",
"chicken",
"dog",
"pig"
)
)
for name, member in Zodiac.__members__.items():
print(
f"name:{name}\tmember:{member}\tindex:{member.value}" # member.value 是自动加上的,默认从1开始
)
"""
name:rat member:Zodiac.rat index:1
name:cattle member:Zodiac.cattle index:2
name:tiger member:Zodiac.tiger index:3
name:rabbit member:Zodiac.rabbit index:4
name:dragon member:Zodiac.dragon index:5
name:snack member:Zodiac.snack index:6
name:horse member:Zodiac.horse index:7
name:sheep member:Zodiac.sheep index:8
name:monkey member:Zodiac.monkey index:9
name:chicken member:Zodiac.chicken index:10
name:dog member:Zodiac.dog index:11
name:pig member:Zodiac.pig index:12
"""
自定义枚举类
from enum import Enum, unique
@unique # 保证没有重复值
class Zodiac(Enum):
rat = 1
cattle = 2
tiger = 3
rabbit = 4
dragon = 5
snack = 6
horse = 7
sheep = 8
monkey = 9
chicken = 10
dog = 11
pig = 12
zod = 1
print(zod == Zodiac.rat.value) # True
(本文完)