day7—直播内容(元昊老师著)

本文深入探讨了Python中类和对象的概念,包括属性管理、动态属性设置、特殊方法如__setattr__和__getattr__的使用,以及如何通过字典构建对象。此外,还介绍了Python中的socket编程基础和示例。
    
*******************************
class animal(object):
def __init__(self):
self.is_handsome=True

def eat(self):
if self.is_handsome:
print "eat...."
else:
print "no handsome"

class dog(animal):
def __init__(self):
#animal.__init__(self)
super(dog,self).__init__()
self.hair="black"

def bite(self):
print "bite me!"

d=dog()
d.bite()
d.eat()

******************************************



我有一个字典,从某个地方获取的,比如http请求发过来的,我要根据这个
字典来构建一个对象。

class Person:
def __init__(self,_obj):
self.name = _obj['name']
self.age = _obj['age']
self.energy = _obj['energy']
self.gender = _obj['gender']
self.email = _obj['email']
self.phone = _obj['phone']
self.country = _obj['country']

class Person:
def __init__(self,_obj):
self.__dict__.update(_obj)


在Python中,所有的东西都是对象,这些对象是由一个类型实例化而来;那么说,
这些对象就有属性和方法,属性可以存储一些值。而从直观上来看,任何可以存储
东西的事物,我们都可以说它有一个空间(只有有空间,才能存储东西嘛),而在
编程中,我们一般使用术语“名字空间”或“命名空间”(namespace)来称呼它。这样,
我们就得出,每个对象都有一个名字空间。而在Python中,我们使用对象的__dict__
属性来保存该对象的名字空间中的东西,__dict__是一个字典(“键-值”对,一般“键”
就是属性名或方法名,“值”就是属性的值或方法名所指向的真正的方法实体对象)。

#__dict__:实例属性
class Animal:
price = 10
__a = 22
def __init__(self):
self.__color = "red"
self.__price = 11

class Dog(Animal):
__b = 10
c = 33

if __name__ == "__main__":
dog=Dog()
print (dog.__dict__)

*******************************************
在Python中,重载__getattr__、__setattr__、__delattr__和__getattribute__
方法可以用来管理一个自定义类中的属性访问。其中,__getattr__方法将拦截所
有未定义的属性获取(即,当要访问的属性已经定义时,该方法不会被调用,至于
定义不定义,是由Python能否查找到该属性来决定的);__getattribute__方法将
拦截所有属性的获取(不管该属性是否已经定义,只要获取它的值,该方法都会调
用),由于此情况,所以,当一个类中同时重载了__getattr__和__getattribute__
方法,那么__getattr__永远不会被调用,另外,__getattribute__方法仅仅存在于
Python2.6的新式类和Python3的所有类中;__setattr__方法将拦截所有的属性赋
值;__delattr__方法将拦截所有的属性删除。说明:在Python中,一个类或类实
例中的属性是动态的(因为Python是动态的),也就是说,你可以往一个类或类实
例中添加或删除一个属性。


1.1 重载__setattr__方法:
在重载__setattr__方法时,不能使用“self.name = value”格式,否则,它将会导致
递归调用而陷入死循环。正确的应该是:

def __setattr__(self, name, value):
# do-something
object.__setattr__(self, name, value)
# do-something

注:其中的“object.__setattr__(self, name, value)”一句可以换成
“self.__dict__[name] = value”;

1.2 重载__delattr__方法:
在重载__delattr__方法时,不能使用del self.name格式,否则,它将会导致递归
调用而陷入死循环。正确的应该是:

def __delattr__(self, name):
# do-something
object.__delattr__(self, name)
# do-something

注:其中的“object.__delattr__(self, name)”一句可以换成
“del self.__dict__[name]”;

1.3 重载__getattribute__方法:

def __getattribute__(self, name):
# do-something
return object.__getattribute__(self, name)
# do-something
在__getattribute__方法中不能把“return object.__getattribute__(self, name)
”一句替换成“return self.__dict__[name]”来避免循环,因为它
(即其中的self.__dict__)也会触发属性获取,进而还是会导致递归调用。

1.4 重载__getattr__方法:
由于__getattr__方法是拦截未定义的属性,所以它没有其他三个操作符方法中那么
多的限制,因此,你可以像正常的代码一样编写它。它的作用就是,当一段代码
(用户写的,可能是故意,也可以是无意)获取了类或类实例中没有定义的属性时,
程序将做出怎样的反应,而这个回应就在__getattr__方法中,由你来定。

************************************************************


class computer(object):
def __init__(self):
self.brand=""
self.color=""

def set_pro(self,pro):
self.brand,self.color=pro
def get_pro(self):
return self.brand,self.color

c=computer()
print c.get_pro()
print c.set_pro(("gaier","red"))
print c.get_pro()

如果我们的属性很多,这种写法就不合适了,我们可以通过拦截属性解决,即将所
有的获取,赋值操作写在一个拦截属性函数里

class computer2(object):
def __init__(self):
self.brand="1"
self.color=""
def __setattr__(self, key, value):
if key=="pro":
self.brand,self.color=value
else:
self.__dict__[key]=value

def __getattr__(self, item):
if item=="pro":
return self.brand,self.color
else:
raise AttributeError
#print "errors..."

c2=computer2()
# c2.pro=("sanxing","blue")
#
# print c2.pro
# c2.a=4
# print c2.a
# print c2.acd
#print c2.brand


c2.money=12
print c2.money
print c2.abc
print c2.__dict__

*******************************************************
2.7编码问题:



python 有str object 和 unicode object 两种字符串, 都可以存放字符的字节编
码,但是他们是不同的type,这一点很重要,也是为什么会有encode 和decode。

encode 和 decode在pyhton 中的意义可表示为

encode
unicode -------------------------> str(gb2312 or utf-8)
unicode <--------------------------str(gb2312 or utf-8)
decode
几种常用法:
str_string.decode('codec') 是把str_string转换为unicode_string, codec是源str_string的编码方式
unicode_string.encode('codec') 是把unicode_string 转换为str_string,codec是目标str_string的编码方式
str_string.decode('from_codec').encode('to_codec') 可实现不同编码的str_string之间的转换
比如:
>>> t='长城'
>>> t
'\xb3\xa4\xb3\xc7'
>>> t.decode('gb2312').encode('utf-8')
'\xe9\x95\xbf\xe5\x9f\x8e'
str_string.encode('codec') 是先调用系统的缺省codec去把str_string转换为
unicode_string,然后用encode的参数codec去转换为最终的str_string. 相当于
str_string.decode('sys_codec').encode('codec')。

*********************************************************
socket(family,type[,protocal]) 使用给定的地址族、套接字类型、协议编号
(默认为0)来创建套接字。

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

服务端socket函数
s.bind(address):将套接字绑定到地址, 在AF_INET下,以元组(host,port)的形式
表示地址.
s.listen(backlog):开始监听TCP传入连接。backlog指定在拒绝连接之前,操作系统
可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。

s.accept():接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可
以用来接收和发送数据。address是连接客户端的地址。

客户端socket函数
s.connect(address):连接到address处的套接字。一般address的格式为元组
(hostname,port),如果连接出错,返回socket.error错误。

s.recv(bufsize[,flag]):接受TCP套接字的数据。数据以字符串形式返回,
bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
s.send(string[,flag]):发送TCP数据。将string中的数据发送到连接的套接字。
返回值是要发送的字节数量,该数量可能小于string的字节大小。
s.sendall(string[,flag]):完整发送TCP数据。将string中的数据发送到连接的套接
字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

s.close()
关闭套接字。
s.getpeername()
返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname()
返回套接字自己的地址。通常是一个元组(ipaddr,port)
*********************************************************
eg1:
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',9997)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
print 'server waiting...'
conn,addr = sk.accept()

client_data = conn.recv(1024)
print client_data
conn.sendall('滚蛋!')

conn.close()
----------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',9997)

sk = socket.socket()
sk.connect(ip_port)

sk.sendall('我喜欢你')

server_reply = sk.recv(1024)
print server_reply

print sk.getpeername()
print "*****"
print sk.getsockname()

sk.close()

***********************************************
eg2:
#!/usr/bin/env python
#coding:utf-8
import socket

def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 201 OKkkkkk\r\n\r\n")
client.send("Hello, World")

def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost',8082))
sock.listen(5)

while True:
connection, address = sock.accept()
handle_request(connection)
connection.close()

if __name__ == '__main__':
main()

***********************************************
eg3(talking):


#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket


ip_port = ('127.0.0.1',8884)
sk = socket.socket()
sk.connect(ip_port)
print "客户端启动:"
while True:
inp = raw_input('>>>')
sk.sendall(inp)
server_response=sk.recv(1024)
print server_response
if inp == 'exit':
break
sk.close()
-----------------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-


import socket

ip_port = ('127.0.0.1',8884)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
print "服务端启动..."
while True:
conn,address = sk.accept()
while True:
try:
client_data=conn.recv(1024)
except Exception:
break
print client_data
print "waiting..."
#server_response=raw_input(">>>")
#conn.sendall(server_response)
conn.sendall(client_data)

conn.close()

注意:
当我们断开第一个客户端时,此时server端 client_data=conn.recv(1024)
这里便会接收一个空字符串,从而造成死循环,而windows系统会将这种情况视为
一个错误,UNIX/linux则不会!所以在linux下,只需判断下client_data为空时break
即可解决!

这个问题与3.0/2.0没有关系


*****************************************************
为了解决并发问题,我们采用socketserver模块


#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

def handle(self):
print "服务端启动..."
while True:
conn = self.request
print self.client_address
while True:
try:
client_data=conn.recv(1024)
except Exception:
break
print client_data
print "waiting..."
#server_response=raw_input(">>>")
#conn.sendall(server_response)
conn.sendall(client_data)

conn.close()
# print self.request,self.client_address,self.server


if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8090),MyServer)
server.serve_forever()
----------------------------------------------------



#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket


ip_port = ('127.0.0.1',8090)
sk = socket.socket()
sk.connect(ip_port)
print "客户端启动:"
while True:
inp = raw_input('>>>')
sk.sendall(inp)
server_response=sk.recv(1024)
print server_response
if inp == 'exit':
break
sk.close()

*****************************************************
ssh:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
import subprocess

class MyServer(SocketServer.BaseRequestHandler):

def handle(self):
print "got connection from",self.client_address
while True:

conn=self.request
data=conn.recv(1024)
print "Recv cmd:%s"%data
cmd_call=subprocess.Popen(data,shell=True,stdout=subprocess.PIPE)

cmd_result=cmd_call.stdout.read()
if len(cmd_result)==0:
cmd_result=b"no output!"
conn.send(str(len(cmd_result)))
#conn.recv(1024)
conn.sendall(cmd_result)# 超过1024的部分放到缓存区,并不阻塞在这里

if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8091),MyServer)
server.serve_forever()


#dir arp cd ipconfig

-------------------------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',8091)
sk = socket.socket()
sk.connect(ip_port)
print "客户端启动:"
while True:
inp = raw_input('>>>')
if len(inp)==0:
continue
if inp=="q":
break
sk.sendall(inp)
res_size=sk.recv(1024)
#sk.send("ok")
print "res_size",res_size
total_size=int(res_size)
received_size=0
while True:

server_response=sk.recv(1024)
received_size+=len(server_response)
if total_size==received_size:

print server_response
break

print server_response


sk.close()

***********************************************************



import os import sqlite3 from datetime import datetime, timedelta from typing import Optional, Dict, Any, List DB_NAME = "cardDetect/employee_checkins.db" def _ensure_db_dir(): os.makedirs(os.path.dirname(DB_NAME), exist_ok=True) def _connect(): _ensure_db_dir() conn = sqlite3.connect(DB_NAME) conn.row_factory = sqlite3.Row return conn def _parse_dt(s: str) -> datetime: """ 解析传入的时间字符串。优先尝试 ISO 8601,其次 "%Y-%m-%d %H:%M:%S" 需要的话你可以再补充其他格式。 """ try: return datetime.fromisoformat(s) except ValueError: return datetime.strptime(s, "%Y-%m-%d %H:%M:%S") # -------- 建表 -------- def create_tables(): """创建员工表 + 打卡表""" conn = _connect() c = conn.cursor() # 员工主表 c.execute( """ CREATE TABLE IF NOT EXISTS employees ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, employee_id TEXT NOT NULL UNIQUE ) """ ) # 打卡表(外键关联员工) c.execute( """ CREATE TABLE IF NOT EXISTS checkins ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, employee_id TEXT NOT NULL, checkin_time TEXT NOT NULL, FOREIGN KEY (employee_id) REFERENCES employees(employee_id) ) """ ) # 常用索引:加速查询 c.execute("CREATE INDEX IF NOT EXISTS idx_checkins_empid ON checkins(employee_id)") c.execute("CREATE INDEX IF NOT EXISTS idx_checkins_time ON checkins(checkin_time)") conn.commit() conn.close() # -------- 员工管理 -------- def register_employee(name: str, employee_id: str) -> Dict[str, Any]: """注册/更新员工信息""" conn = _connect() c = conn.cursor() try: c.execute( """ INSERT INTO employees (name, employee_id) VALUES (?, ?) ON CONFLICT(employee_id) DO UPDATE SET name = excluded.name """, (name, employee_id), ) conn.commit() return {"ok": True} except sqlite3.Error as e: return {"ok": False, "error": f"DB_ERROR: {e}"} finally: conn.close() def employee_exists(name: str, employee_id: str) -> bool: conn = _connect() c = conn.cursor() c.execute( "SELECT 1 FROM employees WHERE employee_id = ? AND name = ? LIMIT 1", (employee_id, name), ) row = c.fetchone() conn.close() return row is not None # -------- 打卡逻辑 -------- def fetch_last_checkin(employee_id: str) -> Optional[sqlite3.Row]: """查询该员工最近一条打卡记录""" conn = _connect() c = conn.cursor() c.execute( """ SELECT id, name, employee_id, checkin_time FROM checkins WHERE employee_id = ? ORDER BY id DESC LIMIT 1 """, (employee_id,), ) row = c.fetchone() conn.close() return row def insert_checkin(name: str, employee_id: str, checkin_time: str) -> Dict[str, Any]: """ 1) 若员工不存在 -> 返回 INVALID_EMPLOYEE 2) 若距上次打卡 < 15 分钟 -> 返回 DUPLICATE_CHECKIN 3) 否则插入成功 """ if not employee_exists(name, employee_id): return {"ok": False, "error": "INVALID_EMPLOYEE", "message": "无效员工"} last = fetch_last_checkin(employee_id) if last: try: last_dt = _parse_dt(last["checkin_time"]) curr_dt = _parse_dt(checkin_time) except ValueError: return { "ok": False, "error": "INVALID_TIME_FORMAT", "message": "时间格式无法解析", } diff = curr_dt - last_dt if diff.total_seconds() < 15 * 60: # 重复打卡 minutes = max(0, int(diff.total_seconds() // 60)) return { "ok": False, "error": "DUPLICATE_CHECKIN", "message": "重复打卡(15 分钟内)", "minutes_since_last": minutes, "last_checkin_time": last["checkin_time"], } # 3. 插入 conn = _connect() c = conn.cursor() try: c.execute( """ INSERT INTO checkins (name, employee_id, checkin_time) VALUES (?, ?, ?) """, (name, employee_id, checkin_time), ) conn.commit() return { "ok": True, "data": { "name": name, "employee_id": employee_id, "checkin_time": checkin_time, "checkin_id": c.lastrowid, }, } except sqlite3.Error as e: return {"ok": False, "error": f"DB_ERROR: {e}"} finally: conn.close() def fetch_last_20_checkins(): """查询最近 20 条打卡记录""" conn = _connect() c = conn.cursor() c.execute( "SELECT name, employee_id, checkin_time FROM checkins ORDER BY id DESC LIMIT 20" ) rows = c.fetchall() conn.close() return rows def delete_employee(employee_id: str) -> Dict[str, Any]: """ 删除指定员工及其所有打卡记录 输入: employee_id - 员工工号 输出: {"ok": bool, "deleted_employees": int, "deleted_checkins": int} """ conn = _connect() c = conn.cursor() try: # 删除关联打卡记录 c.execute("DELETE FROM checkins WHERE employee_id = ?", (employee_id,)) deleted_checkins = c.rowcount # 删除员工记录 c.execute("DELETE FROM employees WHERE employee_id = ?", (employee_id,)) deleted_employees = c.rowcount conn.commit() return { "ok": True, "deleted_employees": deleted_employees, "deleted_checkins": deleted_checkins } except sqlite3.Error as e: conn.rollback() return {"ok": False, "error": f"DB_ERROR: {e}"} finally: conn.close() def get_employee_checkins(employee_id: str) -> List[Dict]: """ 获取指定员工的所有打卡记录 输入: employee_id - 员工工号 输出: 打卡记录列表 [{"id": int, "checkin_time": str}, ...] """ conn = _connect() c = conn.cursor() c.execute(""" SELECT id, checkin_time FROM checkins WHERE employee_id = ? ORDER BY checkin_time DESC """, (employee_id,)) return [dict(row) for row in c.fetchall()] def update_employee(employee_id: str, new_name: str, new_checkins: List[str]) -> Dict[str, Any]: """ 更新员工信息并替换打卡记录 输入: employee_id - 要修改的员工工号 new_name - 新姓名 new_checkins - 新的打卡时间列表 ["2023-01-01 09:00", ...] 输出: {"ok": bool, "updated": int, "new_records": int} """ conn = _connect() c = conn.cursor() try: # 更新员工姓名 c.execute(""" UPDATE employees SET name = ? WHERE employee_id = ? """, (new_name, employee_id)) updated = c.rowcount # 删除原有打卡记录 c.execute("DELETE FROM checkins WHERE employee_id = ?", (employee_id,)) # 插入新记录 new_records = 0 for checkin_time in new_checkins: c.execute(""" INSERT INTO checkins (name, employee_id, checkin_time) VALUES (?, ?, ?) """, (new_name, employee_id, checkin_time)) new_records += 1 conn.commit() return { "ok": True, "updated": updated, "new_records": new_records } except sqlite3.Error as e: conn.rollback() return {"ok": False, "error": f"DB_ERROR: {e}"} finally: conn.close() def get_all_employees() -> List[Dict]: """ 获取所有员工信息 输入: 无 输出: 员工列表 [{"id": int, "name": str, "employee_id": str}, ...] """ conn = _connect() c = conn.cursor() c.execute("SELECT id, name, employee_id FROM employees") return [dict(row) for row in c.fetchall()] def has_checked_in_today(employee_id: str) -> bool: """ 判断员工今日是否已打卡 输入: employee_id - 员工工号 输出: bool (True表示今日已打卡) """ conn = _connect() c = conn.cursor() # 获取最新打卡记录 last_checkin = fetch_last_checkin(employee_id) if not last_checkin: return False # 解析打卡时间 checkin_dt = _parse_dt(last_checkin["checkin_time"]) today = datetime.now().date() return checkin_dt.date() == today # -------------- 示例 -------------- if __name__ == "__main__": create_tables() register_employee("TOM", "18181818") register_employee("EASON", "19191919") register_employee("张亦行", "18085408") register_employee("刘顺源", "18097749") register_employee("沈俊西", "18092383") register_employee("刘元昊", "18083009") print( insert_checkin("TOM", "18181818", datetime.now().strftime("%Y-%m-%d %H:%M:%S")) ) print( insert_checkin( "EASON", "19191919", datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) ) ——现在在main函数中加入对新加入的每个函数的测试
08-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值